
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/signal.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>


#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFFER_SIZE 1024

static void recv_from_alarm(int signal_no);
static int pipe_fd[2];

void recv_from_alarm(int signal_no) {

    write(pipe_fd[1], "", 1);
    return;
}

static int max(int a, int b) {

    return a > b ? a : b;
}

void dg_cli(FILE * fp, int socket_fd, const struct sockaddr * pserv_address, socklen_t server_length) {

    const int on = 1;
    setsockopt(socket_fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));

    int n = 0, max_fd = 0;
    fd_set  read_set;
    char send_line[BUFFER_SIZE], recv_line[BUFFER_SIZE];
    socklen_t len;
    struct sockaddr * preply_address;

    pserv_address = malloc(server_length);

    int result = pipe(pipe_fd);
    printf("create pipe and result : %d\n", result);

    max_fd = max(socket_fd, pipe_fd[0]) + 1;
    FD_ZERO(&read_set);

    signal(SIGALRM, recv_from_alarm);

    while (fgets(send_line, BUFFER_SIZE, fp) != NULL) {

        sendto(socket_fd, send_line, strlen(send_line), 0, pserv_address, server_length);

        alarm(5);
        for (; ; ) {

            FD_SET(pipe_fd[0], &read_set);
            FD_SET(socket_fd,  &read_set);
            if ((n = select(max_fd, &read_set, NULL, NULL, NULL)) < 0) {

                if (errno == EINTR) {

                    continue;
                } 
                else {

                    printf("select error.\n");
                }
            }
            if (FD_ISSET(socket_fd, &read_set)) {

                len = server_length;
                recvfrom(socket_fd, recv_line, BUFFER_SIZE, 0, preply_address, &len);
                recv_line[0] = 0;
                printf("from %s \n", recv_line);
            }
            if (FD_ISSET(pipe_fd[0], &read_set)) {

                // time out
                printf("alarm\n");
                read(pipe_fd[0], &n, 1);
                break;
            }
        }
    }
    free(preply_address);
    close(socket_fd);
    close(pipe_fd[0]);
    close(pipe_fd[1]);
}

int main(int argc, char * argv[]) {

    int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);

    if (sock_fd < 0) {

        printf("create socket fd failure.\n");
        return EXIT_FAILURE;
    }
    struct sockaddr_in sa;
    bzero(&sa, sizeof(sa));

    sa.sin_family = AF_INET;
    sa.sin_port   = htons(13); 
    inet_pton(AF_INET, argv[1], &sa.sin_addr);

    dg_cli(stdin, sock_fd, (struct sockaddr*)&sa, sizeof(sa));
    return EXIT_SUCCESS;
}
// gcc dgcli_bcast_use_select.c -o dgcli_bcast_use_select